package io.aicn.lowcode.generator;

import io.aicn.lowcode.generator.model.*;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

@Component
public class QOVOGenerator {
    
    public void generateQO(GenerationRequest request, TableInfo tableInfo) throws IOException {
        if (!request.isGenerateQO() || request.getQoConfig() == null) {
            return;
        }
        
        QOConfig qoConfig = request.getQoConfig();
        String className = qoConfig.getClassName();
        if (className == null) {
            className = toPascalCase(tableInfo.getTableName()) + "QO";
        }
        
        StringBuilder content = new StringBuilder();
        String fullPackageName = request.getBasePackage() + "." + qoConfig.getPackageName();
        content.append("package ").append(fullPackageName).append(";\n\n");
        
        // 导入
        content.append("import java.io.Serializable;\n");
        content.append("import java.time.*;\n");
        content.append("import java.math.BigDecimal;\n");
        
        if (qoConfig.isLombok()) {
            content.append("import lombok.Data;\n");
        }
        
        if (qoConfig.isSwagger()) {
            content.append("import io.swagger.v3.oas.annotations.media.Schema;\n");
        }
        
        if (qoConfig.isValidation()) {
            content.append("import jakarta.validation.constraints.*;\n");
        }
        
        if (qoConfig.isGeneratePaginationFields()) {
            content.append("import io.swagger.v3.oas.annotations.Parameter;\n");
        }
        
        content.append("\n");
        
        // 类注解
        if (qoConfig.isSwagger()) {
            content.append("@Schema(description = \"").append(tableInfo.getTableComment() != null ? tableInfo.getTableComment() : tableInfo.getTableName()).append("查询对象\")\n");
        }
        
        if (qoConfig.isLombok()) {
            content.append("@Data\n");
        }
        
        // 类定义
        content.append("public class ").append(className);
        if (qoConfig.getSuperClass() != null) {
            content.append(" extends ").append(qoConfig.getSuperClass());
        }
        content.append(" implements Serializable {\n\n");
        
        // serialVersionUID
        if (qoConfig.isSerialVersionUID()) {
            content.append("    private static final long serialVersionUID = 1L;\n\n");
        }
        
        // 字段
        for (ColumnInfo column : tableInfo.getColumns()) {
            generateQOField(content, column, qoConfig);
        }
        
        // 分页字段
        if (qoConfig.isGeneratePaginationFields()) {
            content.append("    @Schema(description = \"页码，从0开始\")\n");
            content.append("    private Integer page = 0;\n\n");
            
            content.append("    @Schema(description = \"每页大小\")\n");
            content.append("    private Integer size = 10;\n\n");
            
            content.append("    @Schema(description = \"排序字段\")\n");
            content.append("    private String sort;\n\n");
        }
        
        // 搜索字段
        if (qoConfig.isGenerateSearchFields()) {
            content.append("    @Schema(description = \"关键字搜索\")\n");
            content.append("    private String keyword;\n\n");
        }
        
        // getter/setter (如果不使用Lombok)
        if (!qoConfig.isLombok()) {
            generateGettersSetters(content, tableInfo.getColumns(), qoConfig);
        }
        
        content.append("}\n");
        
        // 写入文件
        writeToFile(request.getOutputConfig().getOutputDir(), fullPackageName, className, content.toString());
    }
    
    public void generateVO(GenerationRequest request, TableInfo tableInfo) throws IOException {
        if (!request.isGenerateVO() || request.getVoConfig() == null) {
            return;
        }
        
        VOConfig voConfig = request.getVoConfig();
        String className = voConfig.getClassName();
        if (className == null) {
            className = toPascalCase(tableInfo.getTableName()) + "VO";
        }
        
        StringBuilder content = new StringBuilder();
        String fullPackageName = request.getBasePackage() + "." + voConfig.getPackageName();
        content.append("package ").append(fullPackageName).append(";\n\n");
        
        // 导入
        content.append("import java.io.Serializable;\n");
        content.append("import java.time.*;\n");
        content.append("import java.math.BigDecimal;\n");
        
        if (voConfig.isLombok()) {
            content.append("import lombok.Data;\n");
        }
        
        if (voConfig.isSwagger()) {
            content.append("import io.swagger.v3.oas.annotations.media.Schema;\n");
        }
        
        content.append("\n");
        
        // 类注解
        if (voConfig.isSwagger()) {
            content.append("@Schema(description = \"").append(tableInfo.getTableComment() != null ? tableInfo.getTableComment() : tableInfo.getTableName()).append("返回对象\")\n");
        }
        
        if (voConfig.isLombok()) {
            content.append("@Data\n");
        }
        
        // 类定义
        content.append("public class ").append(className);
        if (voConfig.getSuperClass() != null) {
            content.append(" extends ").append(voConfig.getSuperClass());
        }
        content.append(" implements Serializable {\n\n");
        
        // serialVersionUID
        if (voConfig.isSerialVersionUID()) {
            content.append("    private static final long serialVersionUID = 1L;\n\n");
        }
        
        // 字段
        for (ColumnInfo column : tableInfo.getColumns()) {
            if (!isExcludedField(column.getName(), voConfig.getExcludeFields())) {
                generateVOField(content, column, voConfig);
            }
        }
        
        // getter/setter (如果不使用Lombok)
        if (!voConfig.isLombok()) {
            generateGettersSetters(content, tableInfo.getColumns(), voConfig);
        }
        
        content.append("}\n");
        
        // 写入文件
        writeToFile(request.getOutputConfig().getOutputDir(), fullPackageName, className, content.toString());
    }
    
    private void generateQOField(StringBuilder content, ColumnInfo column, QOConfig config) {
        if (config.isSwagger()) {
            content.append("    @Schema(description = \"").append(column.getComment() != null ? column.getComment() : column.getName()).append("\")\n");
        }
        
        if (config.isValidation()) {
            if (!column.getNullable() && (column.getPrimaryKey() == null || !column.getPrimaryKey())) {
                content.append("    @NotNull(message = \"").append(column.getComment() != null ? column.getComment() : column.getName()).append("不能为空\")\n");
            }
            
            if ("String".equals(column.getJavaType()) && column.getLength() > 0) {
                content.append("    @Size(max = ").append(String.valueOf(column.getLength())).append(", message = \"").append(column.getComment() != null ? column.getComment() : column.getName()).append("长度不能超过").append(String.valueOf(column.getLength())).append("\")\n");
            }
        }
        
        content.append("    private ").append(column.getJavaType()).append(" ").append(column.getJavaProperty()).append(";\n\n");
    }
    
    private void generateVOField(StringBuilder content, ColumnInfo column, VOConfig config) {
        if (config.isSwagger()) {
            content.append("    @Schema(description = \"").append(column.getComment() != null ? column.getComment() : column.getName()).append("\")\n");
        }
        
        content.append("    private ").append(column.getJavaType()).append(" ").append(column.getJavaProperty()).append(";\n\n");
    }
    
    private void generateGettersSetters(StringBuilder content, List<ColumnInfo> columns, Object config) {
        for (ColumnInfo column : columns) {
            String fieldName = column.getJavaProperty();
            String methodName = toPascalCase(fieldName);
            String javaType = column.getJavaType();
            
            // getter
            content.append("    public ").append(javaType).append(" get").append(methodName).append("() {\n");
            content.append("        return ").append(fieldName).append(";\n");
            content.append("    }\n\n");
            
            // setter
            content.append("    public void set").append(methodName).append("(").append(javaType).append(" ").append(fieldName).append(") {\n");
            content.append("        this.").append(fieldName).append(" = ").append(fieldName).append(";\n");
            content.append("    }\n\n");
        }
    }
    
    private boolean isExcludedField(String fieldName, String[] excludeFields) {
        if (excludeFields == null) {
            return false;
        }
        
        for (String excludeField : excludeFields) {
            if (fieldName.equals(excludeField)) {
                return true;
            }
        }
        return false;
    }
    
    private String toPascalCase(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        
        StringBuilder result = new StringBuilder();
        boolean nextUpper = true;
        
        for (int i = 0; i < input.length(); i++) {
            char currentChar = input.charAt(i);
            if (currentChar == '_') {
                nextUpper = true;
            } else {
                if (nextUpper) {
                    result.append(Character.toUpperCase(currentChar));
                    nextUpper = false;
                } else {
                    result.append(Character.toLowerCase(currentChar));
                }
            }
        }
        
        return result.toString();
    }
    
    private void writeToFile(String outputDir, String packageName, String className, String content) throws IOException {
        String packagePath = packageName.replace(".", File.separator);
        String dirPath = outputDir + File.separator + "java" + File.separator + packagePath;
        
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        
        File file = new File(dir, className + ".java");
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(content);
        }
    }
}